﻿namespace ImageProcessing
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// Fourier effects functions class
    /// </summary>
    public class FourierEffects
    {
        /// <summary>
        /// Draws the circle.
        /// </summary>
        /// <param name="originalImage">The original image.</param>
        /// <param name="circleRadius">The circle radius.</param>
        /// <param name="mask">The mask.</param>
        /// <returns>
        /// Blank image with drawn circle
        /// </returns>
        public static ImageStructure[,] DrawIdealCircle(ImageStructure[,] originalImage, int circleRadius, out double[,] mask)
        {
            int height = originalImage.GetLength(0);
            int width = originalImage.GetLength(1);

            ImageStructure[,] circleImage = new ImageStructure[height, width];
            mask = new double[height, width];

            int centerX = width / 2;
            int centerY = height / 2;

            int x, y;
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    x = j - centerX;
                    y = i - centerY;

                    if (Math.Sqrt((double)((y * y) + (x * x))) <= circleRadius)
                    {
                        mask[i, j] = 1.0;

                        circleImage[i, j].R = 255;
                        circleImage[i, j].G = 255;
                        circleImage[i, j].B = 255;
                    }
                }
            }

            return circleImage;
        }

        /// <summary>
        /// Draws the butter worth circle.
        /// </summary>
        /// <param name="originalImage">The original image.</param>
        /// <param name="circleRadius">The circle radius.</param>
        /// <param name="n">The n.</param>
        /// <param name="mask">The mask.</param>
        /// <returns>
        /// Image with circle in it
        /// </returns>
        public static ImageStructure[,] DrawButterWorthCircle(ImageStructure[,] originalImage, int circleRadius, int n, out double[,] mask)
        {
            int height = originalImage.GetLength(0);
            int width = originalImage.GetLength(1);

            ImageStructure[,] circleImage = new ImageStructure[height, width];
            mask = new double[height, width];
            int centerX = (int)Math.Floor(width / 2.0);
            int centerY = (int)Math.Floor(height / 2.0);

            int x, y;
            double value;
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    x = j - centerX;
                    y = i - centerY;

                    value = 1 + Math.Pow((Math.Sqrt((double)((y * y) + (x * x))) / circleRadius), (2 * n));
                    value = 1 / value;
                    mask[i, j] = value;
                    value *= 255;

                    circleImage[i, j].R = (byte)value;
                    circleImage[i, j].G = (byte)value;
                    circleImage[i, j].B = (byte)value;
                }
            }

            return circleImage;
        }

        /// <summary>
        /// Draws the gaussian circle.
        /// </summary>
        /// <param name="originalImage">The original image.</param>
        /// <param name="circleRadius">The circle radius.</param>
        /// <param name="mask">The mask.</param>
        /// <returns>
        /// Gaussian circle
        /// </returns>
        public static ImageStructure[,] DrawGaussianCircle(ImageStructure[,] originalImage, int circleRadius, out double[,] mask)
        {
            int height = originalImage.GetLength(0);
            int width = originalImage.GetLength(1);

            ImageStructure[,] circleImage = new ImageStructure[height, width];

            int centerX = width / 2;
            int centerY = height / 2;

            mask = new double[height, width];

            int x, y;
            double value;
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    x = j - centerX;
                    y = i - centerY;

                    value = -1 * Math.Pow(Math.Sqrt((double)((y * y) + (x * x))), 2);
                    value /= 2 * Math.Pow(circleRadius, 2);
                    value = Math.Exp(value);
                    mask[i, j] = value;
                    value *= 255;

                    circleImage[i, j].R = (byte)value;
                    circleImage[i, j].G = (byte)value;
                    circleImage[i, j].B = (byte)value;
                }
            }

            return circleImage;
        }

        /// <summary>
        /// Returns the white image.
        /// </summary>
        /// <param name="originalImage">The original image.</param>
        /// <param name="mask">The mask.</param>
        /// <returns>
        /// White Image
        /// </returns>
        public static ImageStructure[,] ReturnWhiteImage(ImageStructure[,] originalImage, out double[,] mask)
        {
            int height = originalImage.GetLength(0);
            int width = originalImage.GetLength(1);

            ImageStructure[,] circleImage = new ImageStructure[height, width];
            mask = new double[height, width];

            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    circleImage[i, j].R = 255;
                    circleImage[i, j].G = 255;
                    circleImage[i, j].B = 255;
                    mask[i, j] = 1;
                }
            }

            return circleImage;
        }

        /// <summary>
        /// Inverses the mask.
        /// </summary>
        /// <param name="mask">The mask.</param>
        /// <param name="image">The image.</param>
        /// <returns>
        /// Inversed mask
        /// </returns>
        public static double[,] InverseMask(double[,] mask, ref ImageStructure[,] image)
        {
            int height = mask.GetLength(0);
            int width = mask.GetLength(1);

            double[,] newMask = new double[height, width];
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    image[i, j].R = (byte)(255 - image[i, j].R);
                    image[i, j].G = (byte)(255 - image[i, j].G);
                    image[i, j].B = (byte)(255 - image[i, j].B);

                    newMask[i, j] = 1 - mask[i, j];
                }
            }

            return newMask;
        }
    }
}